/**
 * @file utilities.c
 * @brief Utilità dell'applicativo.
 *
 * Vengono definiti in questo sorgente le funzioni e i tipi di dati necessari per il resto dell'applicativo
 * in particolare sono stati definiti:
 * - Strutture e funzionalità per gestire degli array dinamici @see DynArray
 * - Strutture e funzionalità per gestire l'astrazione dei dati @see HiddenType
 * - Funzionalità per gestire le operazioni con le stringhe.
 *
 * @date Feb 27, 2012
 * @author: Francesco Corvino
 */
#include "utilities.h"

/** \brief Si occupa di aggiungere un elemento all'array dinamico.
 *
 * @see DynArray struttura che definisce un'array dinamico.
 * @see removeElementFromDynArray() funzione che rimuove un elemento dall'array.
 */
int addElementToDynArray(DynArray * arr, void * elem){
	int numToAlloc = arr->numelement + 1;
	void *_tmp = realloc(arr->elemBuff,
			(numToAlloc * arr->sizeSingleElem));
	if (!_tmp) {
		return(-1);
	}
	arr->elemBuff = _tmp; // Things are looking good so far
	memcpy( arr->elemBuff + (arr->numelement * arr->sizeSingleElem),
			elem, arr->sizeSingleElem);
	arr->numelement++;
	if(arr->cmpElem!=NULL){
		qsort(arr->elemBuff,
				arr->numelement,arr->sizeSingleElem,
				arr->cmpElem);
	}
	return 0;
}

int removeElementFromDynArray(DynArray * arr, void * elem){
	//TODOL implementare la funzione per rimuove elementi dall'array
	return 0;
}

void * getElementFromDynArray(DynArray * arr, const void * index){
	if(arr->cmpElem!=NULL){ // utilizza la funzione di confronto
		return bsearch(index,arr->elemBuff,
				arr->numelement,arr->sizeSingleElem,
				arr->cmpElem);
	} else { // cerca di convertire in intero l'argomento
		int i = (int) &(index);
		if(i>arr->numelement) return NULL;
		else {
			return (arr->elemBuff + (i*arr->sizeSingleElem));
		}
	}
}

void * HiddenType_executeInterpreter(HiddenType* ht, void * context){
	return (*ht->interpretfnc)(ht->hiddentype, context);
}

/**
 * @brief Esecutore dell'interpretazione delle informazioni presenti in un <code>HiddenType</code>.
 * Interpretatore utilizzato nel caso di dichiarazioni del tipo
 * <code>HiddenType = String | char* (*fn)(void * context) </code>
 * @param value valore dell'hidden type
 * @param context contesto dell'hidden type: se impostato a NULL definisce di non utilizzare la funzione interpretatrice.
 */
char* getHiddenTypeToString(void * value, void * context){
	if(context==NULL) {
		return (char*) value;
	} // interpreta il campo value come un puntatore a funzione char* (*fnc)(void*)
	char* (*some_func)() = (char* (*)(void*)) value;
	return (char*) (*some_func)(context);
}

void logsimplefunction(char*h){
	printf("message log: %s\n",h);
}

int getFirstWord(const char *sourceStr,char *destStr, char* separatorC){
	char *dp, *token;
	if((dp = strdup(sourceStr))==NULL) return -1;
	token =	strsep(&dp,separatorC);
	strcpy(destStr, token);
	//free(dp);
	return 0;
}

/** \brief permette di ottenere una stringa concatenata.
 *
 */
char *getMultipleStrCat (char *String1, ...) {
	va_list List;
	va_start (List, String1);
	unsigned int sizestr;
	sizestr = strlen (String1) + 1;
	char *s = String1;
	do {
		sizestr += strlen (s) + 1;
	} while ((s = va_arg (List, char*)) != NULL);
	char *merge = (char*)malloc (sizeof (char) * sizestr + 1);
	char *sMerge = merge;
	va_end (List);
	va_start (List, String1);
	s = String1;
	do {
		strcpy (merge, s);
		merge += strlen (s);
	} while ((s = va_arg (List, char*)) != NULL);
	va_end (List);
	return sMerge;
}
